package com.elitel.common.minio;

import io.minio.*;
import io.minio.messages.Bucket;
import io.minio.messages.Item;
import org.apache.tomcat.util.http.fileupload.IOUtils;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.util.UriUtils;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;

/**
 * minio 配置工具
 */
@Component
public class MinioTemplate implements InitializingBean {

    @Value(value = "${minio.bucket}")
    private String bucket;

    @Value(value = "${minio.host}")
    private String host;

    @Value(value = "${minio.url}")
    private String url;

    @Value(value = "${minio.access-key}")
    private String accessKey;

    @Value(value = "${minio.secret-key}")
    private String secretKey;

    private MinioClient minioClient;

    @Override
    public void afterPropertiesSet() throws Exception {
        Assert.hasText(url, "Minio url 为空");
        Assert.hasText(accessKey, "Minio accessKey为空");
        Assert.hasText(secretKey, "Minio secretKey为空");
        this.minioClient = new MinioClient(this.host, this.accessKey, this.secretKey);
    }

    public void putObject(String bucketName, String objectName, InputStream inputStream) throws Exception {
        putObject(bucketName, objectName, inputStream, null);
    }

    public void putObject(String bucketName, String objectName, String filePath) throws Exception {
        putObject(bucketName, objectName, new FileInputStream(new File(filePath)), null);
    }
    public void putObject(String bucketName, String objectName, File file) throws Exception {
        putObject(bucketName, objectName, new FileInputStream(file), null);
    }

    public void putObject(String bucketName, String objectName, InputStream inputStream, String contextType) throws Exception {
        putObject(bucketName, objectName, inputStream, inputStream.available(), contextType == null ? MediaType.APPLICATION_OCTET_STREAM_VALUE : contextType);
    }

    public void putObject(String bucketName, String objectName, InputStream inputStream, long size, String contextType) throws Exception {
        //如果bucketExists不存在，创建默认bucketName
        if (!minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build()))
            makeBucket(bucketName);
        try (InputStream in = inputStream) {
            //上传文件
            minioClient.putObject(PutObjectArgs.builder().bucket(bucketName).object(objectName)
                    .stream(in, size, -1)
                    .contentType(contextType)
                    .build());
        }
    }
    /**
     * 上传
     */
    public String putObject(MultipartFile multipartFile) throws Exception {
        String fileName = multipartFile.getOriginalFilename();
        putObject(this.bucket, fileName, multipartFile.getInputStream(), multipartFile.getSize(), multipartFile.getContentType());
        return this.url + UriUtils.encode(fileName, StandardCharsets.UTF_8);
    }

    public InputStream getObject(String bucketName, String objectName) throws Exception {
        if (!minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build()))
            return null;
        return minioClient.getObject(GetObjectArgs.builder().bucket(bucketName).object(objectName).build());
    }
    /**
     * 文件下载
     */
    public void download(String fileName, HttpServletRequest request, HttpServletResponse response){
        // 从链接中得到文件名
        InputStream inputStream;
        try {
            ObjectStat stat = minioClient.statObject(StatObjectArgs.builder().bucket(bucket).object(fileName).build());
            inputStream = getObject(bucket, fileName);
            response.setContentType(stat.contentType());
            response.setCharacterEncoding("UTF-8");
            response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));
            IOUtils.copy(inputStream, response.getOutputStream());
            inputStream.close();
        } catch (Exception e){
            e.printStackTrace();
            System.out.println("有异常：" + e);
        }
    }

    /**
     * 文件下载
     */
    public void download(String bucketName, String objectName, String fileName, HttpServletRequest request, HttpServletResponse response) throws Exception{
        // 从链接中得到文件名
        InputStream inputStream = getObject(bucketName, objectName);
        if (inputStream != null) {
            ObjectStat stat = minioClient.statObject(StatObjectArgs.builder().bucket(bucketName).object(objectName).build());
            response.setContentType(stat.contentType());
            response.setCharacterEncoding("UTF-8");
            String userAgent = request.getHeader("user-agent").toLowerCase(Locale.getDefault());
            String newFileName = "";
            if (!userAgent.contains("msie") && !userAgent.contains("like gecko")) {
                newFileName = new String(fileName.getBytes("UTF-8"), "iso-8859-1");
            } else {
                newFileName = URLEncoder.encode(fileName, "UTF-8");
            }
            response.setHeader("content-disposition", "attachment; filename=" + newFileName);
            IOUtils.copy(inputStream, response.getOutputStream());
            inputStream.close();
        } else {
            throw new Exception("minio异常");
        }
    }

    /**
     * 列出所有存储桶名称
     *
     * @return
     * @throws Exception
     */
    public List<String> listBucketNames()
            throws Exception {
        List<Bucket> bucketList = listBuckets();
        List<String> bucketListName = new ArrayList<>();
        for (Bucket bucket : bucketList) {
            bucketListName.add(bucket.name());
        }
        return bucketListName;
    }

    /**
     * 查看所有桶
     *
     * @return
     * @throws Exception
     */
    public List<Bucket> listBuckets()
            throws Exception {
        return minioClient.listBuckets();
    }

    /**
     * 检查存储桶是否存在
     *
     * @param bucketName
     * @return
     * @throws Exception
     */
    public boolean bucketExists(String bucketName) throws Exception {
        boolean flag = minioClient.bucketExists(bucketName);
        if (flag) {
            return true;
        }
        return false;
    }

    /**
     * 创建存储桶
     *
     * @param bucketName
     * @return
     * @throws Exception
     */
    public boolean makeBucket(String bucketName)
            throws Exception {
        boolean flag = bucketExists(bucketName);
        if (!flag) {
            minioClient.makeBucket(bucketName);
            return true;
        } else {
            return false;
        }
    }

    /**
     * 删除桶
     *
     * @param bucketName
     * @return
     * @throws Exception
     */
    public boolean removeBucket(String bucketName)
            throws Exception {
        boolean flag = bucketExists(bucketName);
        if (flag) {
            Iterable<Result<Item>> myObjects = listObjects(bucketName);
            for (Result<Item> result : myObjects) {
                Item item = result.get();
                // 有对象文件，则删除失败
                if (item.size() > 0) {
                    return false;
                }
            }
            // 删除存储桶，注意，只有存储桶为空时才能删除成功。
            minioClient.removeBucket(bucketName);
            flag = bucketExists(bucketName);
            if (!flag) {
                return true;
            }

        }
        return false;
    }

    /**
     * 列出存储桶中的所有对象
     *
     * @param bucketName 存储桶名称
     * @return
     * @throws Exception
     */
    public Iterable<Result<Item>> listObjects(String bucketName) throws Exception {
        boolean flag = bucketExists(bucketName);
        if (flag) {
            return minioClient.listObjects(bucketName);
        }
        return null;
    }

    /**
     * 列出存储桶中的所有对象名称
     *
     * @param bucketName 存储桶名称
     * @return
     * @throws Exception
     */
    public List<String> listObjectNames(String bucketName) throws Exception {
        List<String> listObjectNames = new ArrayList<>();
        boolean flag = bucketExists(bucketName);
        if (flag) {
            Iterable<Result<Item>> myObjects = listObjects(bucketName);
            for (Result<Item> result : myObjects) {
                Item item = result.get();
                listObjectNames.add(item.objectName());
            }
        }
        return listObjectNames;
    }

    /**
     * 删除一个对象
     *
     * @param bucketName 存储桶名称
     * @param objectName 存储桶里的对象名称
     * @throws Exception
     */
    public boolean removeObject(String bucketName, String objectName) throws Exception {
        boolean flag = bucketExists(bucketName);
        if (flag) {
            List<String> objectList = listObjectNames(bucketName);
            for (String s : objectList) {
                if(s.equals(objectName)){
                    minioClient.removeObject(bucketName, objectName);
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * 文件访问路径
     *
     * @param bucketName 存储桶名称
     * @param objectName 存储桶里的对象名称
     * @return
     * @throws Exception
     */
    public String getObjectUrl(String bucketName, String objectName) throws Exception {
        boolean flag = bucketExists(bucketName);
        String url = "";
        if (flag) {
            url = minioClient.getObjectUrl(bucketName, objectName);
        }
        return url;
    }

}

